import socket
import time
import serial
import threading
import struct
import keyboard

# 设备信息
ip_address = '192.168.10.11'
port = 5020

# 要读取的寄存器地址,Modbus TCP 请求帧：是否存在撕裂
register_address_if = 0x003  # 适当设置要读取的寄存器地址
transaction_id = 0x1234
unit_id = 0x01
function_code_if = 0x01

# 建立撕裂数请求帧
register_address_num = 0x014
function_code_num = 0x04

# 建立撕裂最大长度请求帧
register_address_Length = 0x015
function_code_Length = 0x04


def ExistTear(register_address):
    return bytearray([
        transaction_id >> 8, transaction_id & 0xFF,
        0x00, 0x00,  # Protocol Identifier
        0x00, 0x06,  # Length
        unit_id,
        function_code_if,
        register_address >> 8, register_address & 0xFF,
        0x00, 0x01  # Read one register
    ])


##########################################################################################
# 撕裂数目信息发送帧
def TearNum(register_address):
    return bytearray([
        transaction_id >> 8, transaction_id & 0xFF,
        0x00, 0x00,  # Protocol Identifier
        0x00, 0x06,  # Length
        unit_id,
        function_code_num,
        register_address >> 8, register_address & 0xFF,
        0x00, 0x01  # Read one register
    ])


##########################################################################################
# 最大撕裂长度信息发送帧
def TearLength(register_address):
    return bytearray([
        transaction_id >> 8, transaction_id & 0xFF,
        0x00, 0x00,  # Protocol Identifier
        0x00, 0x06,  # Length
        unit_id,
        function_code_Length,
        register_address >> 8, register_address & 0xFF,
        0x00, 0x02  # Read one register
    ])


# 创建 Socket 连接
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((ip_address, port))

# RS485串口配置
SERIAL_PORT = 'COM6'  # 串口名称
BAUD_RATE = 9600  # 波特率

# 创建一个锁，以确保线程间的安全访问串口
serial_lock = threading.Lock()
running_flag = True


def send_command():
    try:
        total_time = 0
        pre_i2 = 0
        while running_flag:
            with serial_lock:
                try:
                    # 创建RS485串口连接
                    ser = serial.Serial(SERIAL_PORT, BAUD_RATE)
                    # 构建请求帧
                    request_frame = ExistTear(register_address_if)

                    # 发送请求帧
                    client_socket.send(request_frame)

                    # 接收响应帧
                    response_frame = client_socket.recv(1024)

                    # 解析响应帧
                    if len(response_frame) >= 9 and response_frame[7] == function_code_if:
                        # data = response_frame[9] << 8 | response_frame[10]
                        i1 = int.from_bytes(response_frame[9:], byteorder='big', signed=True)
                        if i1 == 0:
                            print("未发现皮带撕裂。")
                        elif i1 == 1:
                            print("皮带出现撕裂！")

                    ##########################################################################################
                    # 撕裂数目信息请求

                    request_frame_num = TearNum(register_address_num)

                    # 发送请求帧
                    client_socket.send(request_frame_num)

                    # 接收响应帧
                    response_frame_num = client_socket.recv(1024)

                    # 解析响应帧
                    if len(response_frame_num) >= 9 and response_frame_num[7] == function_code_num:
                        # data = response_frame[9] << 8 | response_frame[10]
                        i2 = int.from_bytes(response_frame_num[9:], byteorder='big', signed=True)

                        if i2 != 0:
                            print("皮带撕裂数:", i2)

                            if pre_i2 != i2:
                                pre_i2 = i2
                                total_time = 0

                            # 设置声光报警器时间
                            if total_time < 3 and i2 == pre_i2:
                                start_time = time.time()
                                hex_data = bytes.fromhex('01 10 00 10 00 01 02 00 05 64 C3')
                                ser.write(hex_data)
                                time.sleep(0.5)
                                elapsed_time = time.time() - start_time
                                total_time += elapsed_time
                                # print(total_time)

                            elif total_time > 3:
                                hex_data_stop = bytes.fromhex('01 10 00 10 00 01 02 00 00 A4 C0')
                                ser.write(hex_data_stop)
                                time.sleep(0.5)

                    else:
                        print("Modbus Read Error")

                    ##########################################################################################
                    # 撕裂最大长度请求

                    request_frame_Length = TearLength(register_address_Length)

                    # 发送请求帧
                    client_socket.send(request_frame_Length)

                    # 接收响应帧
                    response_frame_Length = client_socket.recv(1024)

                    # 解析响应帧
                    if len(response_frame_Length) >= 9 and response_frame_Length[7] == function_code_Length:
                        # data = response_frame_Length[9] << 8 | response_frame_Length[10]
                        i3 = struct.unpack('!f', response_frame_Length[9:])[0]
                        # print("皮带最大撕裂长度:", i3)
                        if i3 != 0:
                            print("皮带最大撕裂长度:", i3)

                    # print("Command sent:", command_to_send)

                except serial.SerialException as e:
                    print("Serial communication error:", e)
                    # print("报警装置连接失败.")
                finally:
                    ser.close()

            time.sleep(1)

    except KeyboardInterrupt:

        pass


def check_serial_connection(port, baud_rate):
    try:

        ser1 = serial.Serial(port, baud_rate)
        ser1.close()
        return True
    except serial.SerialException:
        return False


def monitor_connection():
    try:
        while running_flag:
            with serial_lock:
                try:
                    ser = serial.Serial(SERIAL_PORT, BAUD_RATE)
                    if ser.is_open:
                        print("报警装置连接成功.")
                    else:
                        print("报警装置连接失败.")

                    if keyboard.is_pressed('e'):
                        break
                except serial.SerialException as e:
                    # print("Serial communication error:", e)
                    print("报警装置连接失败.")
                finally:
                    ser.close()

            time.sleep(5)
    except KeyboardInterrupt:
        pass


def check_connection(ip, port):
    try:
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client_socket.settimeout(1)  # 设置超时时间为1秒
        client_socket.connect((ip, port))
        client_socket.close()
        return True
    except Exception as e:
        return False

def FrontConnect():
    try:
        while running_flag:
            with serial_lock:
                connection_status = check_connection(ip_address, port)
                if connection_status:
                    print("检测仪连接成功.")
                else:
                    print("检测仪连接失败！！")

            time.sleep(5)
    except KeyboardInterrupt:
        # 当用户按下Ctrl+C时，终止循环并关闭连接
        pass


# if __name__ == "__main__":
# 创建发送指令和监控连接状态的线程
command_thread = threading.Thread(target=send_command)
monitor_thread = threading.Thread(target=monitor_connection)
FrontConnect_thread = threading.Thread(target=FrontConnect)

# 启动线程
command_thread.start()
monitor_thread.start()
FrontConnect_thread.start()

try:
    while True:
        time.sleep(1)

except KeyboardInterrupt:
    running_flag = False

    command_thread.join()
    monitor_thread.join()
    FrontConnect_thread.join()
